home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Snippets / DeepMaskBlitting / DeepBlitting.p < prev    next >
Text File  |  1997-04-03  |  19KB  |  546 lines

  1. {This is a demo written by Jonathan Apple <KEROI@aol.com>, based on the demo GraphicsBuffers.}
  2.  
  3. {Changes by Ingemar:}
  4. {}
  5. {- Put the drawing code in a case statement, controlled by the constant kChosenBlitType.}
  6. {- Added three variants on the QuickDraw drawing code, all significantly faster than the old}
  7. {CopyBits/CopyMask variant (kDeepCopyMaskType), which was horribly slow due to using CopyMask}
  8. {with an 8-bit mask.}
  9. {- Drawing variant and sprite size is selectable through a dialog.}
  10. {- Fixed bugs in the timing code.}
  11. {- Made sure that CopyBits and CopyMask doesn't have to do any resizing. (IMPORTANT!)}
  12. {- Added a hole in the mask, to make the mask region test more fair (harder for CopyBits!)}
  13. {- Checks for 8-bit screen, 32-bit addressing and Color QD.}
  14. {- Think Pascal compatible. (Sorry about all IFC's...)}
  15. {- Formatted (with Think) and made the capitalizations much closer to standard (types and routines}
  16. {capitalized, variables not.)}
  17. {- Flushed the mouseDown.}
  18. {- Replaced SetRect for the animation loop for a small speed increase.}
  19.  
  20. {Some comments:}
  21.  
  22. {CopyMask is known as the SLOW call for drawing, while CopyBits is the faster one, especially on 68k Macs.}
  23. {CopyMask is particularly slow when using a deep mask. That variant should only be used when you take}
  24. {advantage of the deep mask for anti-aliasing etc. CopyBits will beat it even with 1-bit mask.}
  25.  
  26. {The blitters have no problem to "win" the contest as long as the areas being copied are small.}
  27. {However, with large areas and no masking, CopyBits will not be far behind - or even get ahead!}
  28. {It did in my tests!}
  29.  
  30. {The custom blitter seems a bit buggy. The hole in the mask was no problem for CopyBits and CopyMask,}
  31. {but the custom blitter misbehaves a bit. Also, I don't like the little added size on the rect that the custom}
  32. {blitter needs. No, I don't know what it wrong with it. Try copying the blitter in my BloatBlitDemo for SAT}
  33. {if you like - I think it works better.}
  34.  
  35. {Some junk is left, outcommented code that I didn't remove.}
  36.  
  37. program DeepBlitting;
  38.  
  39.     uses
  40. {$IFC UNDEFINED THINK_PASCAL}
  41.         Types, QuickDraw, OSUtils, SegLoad, Fonts, Windows, Menus, TextEdit, Dialogs,{}
  42.         Processes, Events, QuickDrawText, Types, QuickDraw, OSUtils, SegLoad, Fonts,{}
  43.         Windows, Menus, TextEdit, Dialogs, Events, QuickDrawText, QuickDraw, Icons, {}
  44.         TextUtils, Controls, 
  45. {$ELSEC}
  46. {$SETC GENERATINGPOWERPC := FALSE}
  47. {$ENDC}
  48.         QDOffScreen;
  49.  
  50.     const
  51.         kDeepBlitType = 1;
  52.         kDeepCopyMaskType = 2;
  53.         kCopyBitsMaskType = 3;
  54.         kCopyBitsRgnType = 4;
  55.         kCopyBitsRectType = 5;
  56.  
  57.     var
  58. {The size of the sprite:}
  59.         theSize: Integer; {Suggested values: 50, 100, 300}
  60. {The drawing type we want:}
  61.         gChosenBlitType: Integer;
  62.  
  63.     var
  64.         curDev: GDHandle;
  65.         myErr: OSErr;
  66.         tempRect: Rect;
  67.         pnt: Point;
  68.         windRect: Rect;
  69.         mainPtr: WindowPtr;
  70.         myGDHandle: GDHandle;
  71.         spriteHandle, maskHandle, bgHandle: PicHandle;
  72.         offRect, offMaskRect, spriteRect, spriteRect2: Rect;
  73.         spriteWorld, maskWorld, curPort, workWorld, bgWorld: GWorldPtr;
  74.         maskRgn, tempRgn: RgnHandle;
  75.  
  76.         finTime, initTime, lapseTime: Longint;
  77.         frameCnt: Longint;
  78.         framesPerSec, numSecs: Longint;
  79.         StrBuff: Str255;
  80.  
  81.         {This function, by Matt Formica, merges rects}
  82.     function MergeRect (Rect1, Rect2: Rect): Rect;
  83.         var
  84.             tempRect: Rect;
  85.     begin
  86.         if Rect1.left < rect2.left then
  87.             MergeRect.left := rect1.left
  88.         else
  89.             MergeRect.left := Rect2.left;
  90.         if Rect1.top < rect2.top then
  91.             MergeRect.top := rect1.top
  92.         else
  93.             MergeRect.top := Rect2.top;
  94.         if Rect1.right > rect2.right then
  95.             MergeRect.right := rect1.right
  96.         else
  97.             MergeRect.right := Rect2.right;
  98.         if Rect1.bottom > rect2.bottom then
  99.             MergeRect.bottom := rect1.bottom
  100.         else
  101.             MergeRect.bottom := Rect2.bottom;
  102.     end; {MergeRect}
  103.  
  104.  
  105. {$PUSH}
  106. {$D-}
  107.     procedure Copy8BitsII (srcPix, destPix: PixMapHandle; srcR, destR: Rect); {this works like CopyBits}
  108.         var
  109.             destMemPtr: longintPtr; { Location in memory }
  110.             srcMemPtr: longintPtr;
  111.             numRowsToCopy: integer;
  112.             loopsPerRow: integer;
  113.             srcRowLongsOffset: integer; { rowbytes converted to long }
  114.             destRowLongsOffset: integer;  { rowbytes converted to long }
  115.             srcStripRowBytes: longint; { to clear high bit of rowbytes }
  116.             destStripRowBytes: longint;
  117.             numRowLongs: integer; { number of long words per row }
  118.             pt: Point;
  119.     begin
  120.  { High bit of pixMap rowBytes must be cleared }
  121.         srcStripRowBytes := BAnd($7FFF, srcPix^^.rowBytes);
  122.         destStripRowBytes := BAnd($7FFF, destPix^^.rowBytes);
  123.  { Calculate starting addresses of where to blit... }
  124.         pt := srcR.topLeft;
  125.         LocalToGlobal(pt);
  126.         srcMemPtr := LongintPtr(ORD4(GetPixBaseAddr(srcPix)) + (srcStripRowBytes * pt.v) + pt.h);
  127.         pt := destR.topLeft;
  128.         LocalToGlobal(pt);
  129.         destMemPtr := LongintPtr(ORD4(GetPixBaseAddr(destPix)) + (destStripRowBytes * pt.v) + pt.h);
  130.         numRowsToCopy := srcR.bottom - srcR.top;
  131.         numRowLongs := BSR((srcR.right - srcR.left), 2);
  132.  { Calculate the long word offset from the end of one }
  133.  { row of the source image on the screen's pixmap to the }
  134.  { first byte of the image in the next row. }
  135.         srcRowLongsOffset := BSR(srcStripRowBytes, 2) - numRowLongs;
  136.         destRowLongsOffset := BSR(destStripRowBytes, 2) - numRowLongs;
  137.  { Draw source image directly onto the screen }
  138.         while numRowsToCopy > 0 do
  139.             begin
  140.                 loopsPerRow := numRowLongs;
  141.                 while loopsPerRow > 0 do
  142.                     begin
  143.                         destmemPtr^ := srcmemPtr^;
  144.                         destmemPtr := LongintPtr(ORD4(destmemPtr) + sizeof(Longint));
  145.                         srcmemPtr := LongintPtr(ORD4(srcmemPtr) + sizeof(Longint));
  146.    {*destMemPtr++ = *srcMemPtr++;}
  147. {$IFC UNDEFINED THINK_PASCAL}
  148.                         dec(loopsPerRow);
  149. {$ELSEC}
  150.                         loopsPerRow := loopsPerRow - 1;
  151. {$ENDC}
  152.                     end;
  153.   { Bump to start of next row }
  154.                 srcMemPtr := LongintPtr(ORD4(srcMemPtr) + sizeof(Longint) * srcRowLongsOffset);
  155.                 destMemPtr := LongintPtr(ORD4(destMemPtr) + sizeof(Longint) * destRowLongsOffset);
  156. {$IFC UNDEFINED THINK_PASCAL}
  157.                 dec(numRowsToCopy);
  158. {$ELSEC}
  159.                 numRowsToCopy := numRowsToCopy - 1;
  160. {$ENDC}
  161.             end;
  162.     end; { of Copy8BitsII }
  163.  
  164.  
  165.     procedure Mask8BitsII (srcPix, maskPix, destPix: PixMapHandle; srcR, maskR, destR: Rect); {this is like CopyMask}
  166.  
  167.         var
  168.             destMemPtr: longintPtr; { Location in memory }
  169.             srcMemPtr: longintPtr;
  170.             maskMemPtr: longintPtr;
  171.             numRowsToCopy: integer;
  172.             loopsPerRow: integer;
  173.             srcRowLongsOffset: integer; { rowbytes converted to long }
  174.             destRowLongsOffset: integer;  { rowbytes converted to long }
  175.             maskRowLongsOffset: integer;
  176.             srcStripRowBytes: longint; { to clear high bit of rowbytes }
  177.             destStripRowBytes: longint;
  178.             maskStripRowBytes: longint;
  179.             numRowLongs: integer; { number of long words per row }
  180.             pt: Point;
  181.  
  182.     begin
  183.  { High bit of pixMap rowBytes must be cleared }
  184.         srcStripRowBytes := BAnd($7FFF, srcPix^^.rowBytes);
  185.         destStripRowBytes := BAnd($7FFF, destPix^^.rowBytes);
  186.         maskStripRowBytes := BAnd($7FFF, maskPix^^.rowBytes);
  187.  { Calculate starting addresses of where to blit... }
  188.         pt := srcR.topLeft;
  189.         LocalToGlobal(pt);
  190.         srcMemPtr := LongintPtr(ORD4(GetPixBaseAddr(srcPix)) + (srcStripRowBytes * pt.v) + pt.h);
  191.         pt := maskR.topLeft;
  192.         maskMemPtr := LongintPtr(ORD4(GetPixBaseAddr(maskPix)) + (maskStripRowBytes * pt.v) + pt.h);
  193.         pt := destR.topLeft;
  194.         LocalToGlobal(pt);
  195.         destMemPtr := LongintPtr(ORD4(GetPixBaseAddr(destPix)) + (destStripRowBytes * pt.v) + pt.h);
  196.         numRowsToCopy := srcR.bottom - srcR.top;
  197.         numRowLongs := BSR((srcR.right - srcR.left), 2);
  198.  { Calculate the long word offset from the end of one }
  199.  { row of the source image on the screen's pixmap to the }
  200.  { first byte of the image in the next row. }
  201.         srcRowLongsOffset := BSR(srcStripRowBytes, 2) - numRowLongs;
  202.         destRowLongsOffset := BSR(destStripRowBytes, 2) - numRowLongs;
  203.         maskRowLongsOffset := BSR(maskStripRowBytes, 2) - numRowLongs;
  204.  { Draw source image directly onto the screen }
  205.         while numRowsToCopy > 0 do
  206.             begin
  207.                 loopsPerRow := numRowLongs;
  208.                 while loopsPerRow > 0 do
  209.                     begin
  210.                         destmemPtr^ := Bor(BAnd(destmemPtr^, maskmemPtr^), srcmemPtr^);
  211.                         destmemPtr := LongintPtr(ORD4(destmemPtr) + sizeof(Longint));
  212.                         srcmemPtr := LongintPtr(ORD4(srcmemPtr) + sizeof(Longint));
  213.                         maskmemPtr := LongintPtr(ORD4(maskmemPtr) + sizeof(Longint));
  214.    {*destMemPtr++ = *srcMemPtr++;}
  215. {$IFC UNDEFINED THINK_PASCAL}
  216.                         dec(loopsPerRow);
  217. {$ELSEC}
  218.                         loopsPerRow := loopsPerRow - 1;
  219. {$ENDC}
  220.                     end;
  221.   { Bump to start of next row }
  222.                 srcMemPtr := LongintPtr(ORD4(srcMemPtr) + sizeof(Longint) * srcRowLongsOffset);
  223.                 destMemPtr := LongintPtr(ORD4(destMemPtr) + sizeof(Longint) * destRowLongsOffset);
  224.                 maskMemPtr := LongintPtr(ORD4(maskMemPtr) + sizeof(Longint) * maskRowLongsOffset);
  225. {$IFC UNDEFINED THINK_PASCAL}
  226.                 dec(numRowsToCopy);
  227. {$ELSEC}
  228.                 numRowsToCopy := numRowsToCopy - 1;
  229. {$ENDC}
  230.             end;
  231.     end; { of Mask8BitsII }
  232. {$POP}
  233.  
  234.     procedure Initialize;
  235.         var
  236.             mainPtr: WindowPtr;
  237.             error: OSErr;
  238.             theWorld: SysEnvRec;
  239.     begin
  240. {$IFC UNDEFINED THINK_PASCAL}
  241.         InitGraf(@qd.thePort);
  242.         InitFonts;
  243.         InitWindows;
  244.         InitMenus;
  245.         TEInit;
  246.         InitDialogs(nil);
  247. {$ENDC}
  248.         InitCursor;
  249.     end; {Initialize}
  250.  
  251.     var
  252.         theSysEnv: SysEnvRec;
  253.         dlog: DialogPtr;
  254.         itemHit: Integer;
  255.  
  256. {Just to be independent of my compatibility glue (which I usually all get from InterfacesUI.p):}
  257. {$IFC UNDEFINED THINK_PASCAL}
  258. {$ELSEC}
  259.     procedure GetDialogItem (theDialog: DialogPtr; itemNo: INTEGER; var itemType: INTEGER; var item: Handle; var box: Rect);
  260.     inline
  261.         $A98D;
  262.     procedure SetControlValue (theControl: ControlHandle; theValue: INTEGER);
  263.     inline
  264.         $A963;
  265. {$ENDC}
  266.  
  267.     procedure SetBooleanDItem (itemNo: integer; theBoolean: Boolean);
  268.         var
  269.             kind: integer;
  270.             item: ControlHandle;
  271.             box: Rect;
  272.     begin
  273.         GetDialogItem(FrontWindow, itemNo, kind, Handle(item), box);
  274.         SetControlValue(item, integer(theBoolean));
  275.     end; {SetBooleanDItem}
  276.  
  277. {I replace SetRect to avoid unnecessary context switches in PPC code and to avoid trap calls}
  278. {in 68k code. It will save time for both.}
  279.     procedure MySetRect (var r: Rect; left, top, right, bottom: Integer);
  280.     begin
  281.         r.left := left;
  282.         r.top := top;
  283.         r.right := right;
  284.         r.bottom := bottom;
  285.     end;
  286.  
  287. begin
  288.     Initialize; {sets up all the stuff we need. We do this in CW, not in TP}
  289.  
  290. {Some environment checks! Real programs fire up alerts informing about the problem.}
  291.  
  292. {We must have Color QD!}
  293.     myErr := SysEnvirons(1, theSysEnv);
  294.     if myErr <> noErr then
  295.         begin
  296.             SysBeep(1);
  297.             ExitToShell;
  298.         end;
  299.     if not theSysEnv.hasColorQD then
  300.         begin
  301.             SysBeep(1);
  302.             ExitToShell;
  303.         end;
  304. {We must run in 8-bit! Real applications try to set the screen to that depth.}
  305.     if GetMainDevice^^.gdPMap^^.pixelSize <> 8 then
  306.         begin
  307.             SysBeep(1);
  308.             ExitToShell;
  309.         end;
  310. {When blitting to screen, we must also be in 32-bit mode, or check that the screen}
  311. {is reachable in 24-bit mode.}
  312. {$IFC GENERATINGPOWERPC=FALSE }
  313.     if GetMMUMode = false32b then
  314.         begin
  315.             SysBeep(1);
  316.             ExitToShell;
  317.         end;
  318. {$ENDC}
  319.  
  320.     dlog := GetNewDialog(128, nil, WindowPtr(-1));
  321.     SetPort(dlog);
  322.     SetBooleanDItem(6, true);
  323.     theSize := 50;
  324.     itemHit := 0;
  325.     repeat
  326.         ModalDialog(nil, itemHit);
  327.         if itemHit in [6, 7, 8] then
  328.             begin
  329.                 SetBooleanDItem(6, itemHit = 6);
  330.                 SetBooleanDItem(7, itemHit = 7);
  331.                 SetBooleanDItem(8, itemHit = 8);
  332.                 case itemHit of
  333.                     6: 
  334.                         theSize := 50;
  335.                     7: 
  336.                         theSize := 100;
  337.                     8: 
  338.                         theSize := 300;
  339.                 end;{case}
  340.             end;
  341.     until itemHit in [kDeepBlitType..kCopyBitsRectType];
  342.     gChosenBlitType := itemHit;
  343.     DisposeDialog(dlog);
  344.  
  345.     HideCursor;{Having the cursor on the screen messes up the blitting}
  346.     SetRect(windRect, 0, 0, 640, 480);
  347.     mainPtr := NewCWindow(nil, windRect, 'Pascal Blitting Test', TRUE, documentProc, Pointer(-1), FALSE, 0);
  348.     SetPort(mainPtr);                        { set window to current graf port   }
  349.     GetGWorld(curPort, myGDHandle);
  350.     bgHandle := GetPicture(1);
  351.     spriteHandle := GetPicture(2);
  352.     maskHandle := GetPicture(3);
  353.  
  354.     SetRect(offRect, 0, 0, theSize, theSize);
  355.     {SetRect(offRect, 0, 0, 50, 50);}
  356.     {SetRect(offRect,0,0,100,100);}
  357. {For bigger tests}
  358.     {SetRect(offRect,0,0,300,300);}
  359. {For bigger tests}
  360.  
  361.     SetRect(offMaskRect, 0, 0, theSize, theSize);
  362. {SetRect(offMaskRect, 0, 0, 50, 50);}
  363.     {SetRect(offMaskRect,0,0,100,100);}
  364. {For bigger tests}
  365.     {SetRect(offMaskRect,0,0,300,300);}
  366. {For bigger tests}
  367.  
  368. {$IFC UNDEFINED THINK_PASCAL}
  369.     myErr := NewGWorld(spriteWorld, 8, offRect, nil, nil, 0); {Make a world with the sprite}
  370. {$ELSEC}
  371.     myErr := NewGWorld(spriteWorld, 8, offRect, nil, nil, []); {Make a world with the sprite}
  372. {$ENDC}
  373.     GetGWorld(CGrafPtr(curPort), curDev);
  374.     SetGWorld(spriteWorld, nil);
  375.     if LockPixels(spriteWorld^.portPixMap) then
  376.         begin
  377. {Put Sprites in world using DrawPicture}
  378.             EraseRect(offRect);
  379.             DrawPicture(spriteHandle, offRect);
  380.         end;
  381.     UnlockPixels(spriteWorld^.portPixMap);
  382.     SetGWorld(CGrafPtr(curPort), curDev);
  383.  
  384.     if gChosenBlitType in [kCopyBitsMaskType, kCopyBitsRgnType, kCopyBitsRectType] then
  385. {$IFC UNDEFINED THINK_PASCAL}
  386.         myErr := NewGWorld(maskWorld, 1, offRect, nil, nil, 0)    {Make 1-bit world with the mask}
  387. {$ELSEC}
  388.         myErr := NewGWorld(maskWorld, 1, offRect, nil, nil, [])        {Make 1-bit world with the mask}
  389. {$ENDC}
  390.     else
  391. {$IFC UNDEFINED THINK_PASCAL}
  392.         myErr := NewGWorld(maskWorld, 8, offRect, nil, nil, 0);    {Make a world with the mask}
  393. {$ELSEC}
  394.     myErr := NewGWorld(maskWorld, 8, offRect, nil, nil, []);    {Make a world with the mask}
  395. {$ENDC}
  396.  
  397.     GetGWorld(CGrafPtr(curPort), curDev);
  398.     SetGWorld(maskWorld, nil);
  399.     if LockPixels(maskWorld^.portPixMap) then
  400.         begin
  401. {Put Sprites in world using DrawPicture}
  402.             EraseRect(offMaskRect);
  403.             DrawPicture(maskHandle, offMaskRect);
  404. {Guess what: The mask is white, instead of black. For the copyBits}
  405. {part, we must invert the rect:}
  406.             if gChosenBlitType <> kDeepBlitType then
  407.                 InvertRect(offMaskRect);
  408.         end;
  409.     UnlockPixels(maskWorld^.portPixMap);
  410.     SetGWorld(CGrafPtr(curPort), curDev);
  411.  
  412.     if gChosenBlitType in [kCopyBitsRgnType, kCopyBitsRectType] then
  413.         begin
  414.             maskRgn := NewRgn;
  415.             myErr := BitMapToRegion(maskRgn, GrafPtr(maskWorld)^.portBits);
  416.             tempRgn := NewRgn;
  417.         end;
  418.  
  419.  
  420. {$IFC UNDEFINED THINK_PASCAL}
  421.     myErr := NewGWorld(bgWorld, 8, windRect, nil, nil, 0); {Make a background world}
  422. {$ELSEC}
  423.     myErr := NewGWorld(bgWorld, 8, windRect, nil, nil, []); {Make a background world}
  424. {$ENDC}
  425.     GetGWorld(CGrafPtr(curPort), curDev);
  426.     SetGWorld(bgWorld, nil);
  427.     if LockPixels(bgWorld^.portPixMap) then
  428.         begin
  429. {Put Sprites in world using DrawPicture}
  430.             EraseRect(windRect);
  431.             DrawPicture(bgHandle, windRect);
  432.         end;
  433.     UnlockPixels(bgWorld^.portPixMap);
  434.     SetGWorld(CGrafPtr(curPort), curDev);
  435.  
  436. {$IFC UNDEFINED THINK_PASCAL}
  437.     myErr := NewGWorld(workWorld, 8, windRect, nil, nil, 0); {Make a dirty work world}
  438. {$ELSEC}
  439.     myErr := NewGWorld(workWorld, 8, windRect, nil, nil, []); {Make a dirty work world}
  440. {$ENDC}
  441.     GetGWorld(CGrafPtr(curPort), curDev);
  442.     SetGWorld(workWorld, nil);
  443.     if LockPixels(workWorld^.portPixMap) then
  444.         begin
  445. {Put Sprites in world using DrawPicture}
  446.             EraseRect(windRect);
  447.             DrawPicture(bgHandle, windRect);
  448.         end;
  449.     UnlockPixels(workWorld^.portPixMap);
  450.     SetGWorld(CGrafPtr(curPort), curDev);
  451.     SetGWorld(curPort, nil);
  452.     {This is for the timing/fps calculations:}
  453.     InitTime := TickCount;
  454.     frameCnt := 0;
  455.     DrawPicture(bgHandle, windRect);
  456.  
  457.     repeat
  458.         frameCnt := frameCnt + 1;{fps calc.}
  459.         GetMouse(pnt); {Hey! Where IS that mouse?}
  460. {SetRect(spriteRect, pnt.h, pnt.v, pnt.h + 51, pnt.v + 51);}
  461. {    Make the sprite's}
  462. {    rect where the mouse is. Notice that I am adding 51 to the mouse's position.}
  463. {    I'm pretty sure the reason is cause the mask is 1 pixels smaller than the sprite.}
  464.  
  465.     {SetRect(spriteRect,pnt.h,pnt.v,pnt.h+103,pnt.v+103);}
  466. {For bigger tests. }
  467. {    It's adding 3 cause of the messed up mask for both of these. }
  468. {    Sorry, didn't feel like going back to fix it!}
  469.     {SetRect(spriteRect,pnt.h,pnt.v,pnt.h+303,pnt.v+303);}
  470.  {For bigger test}
  471.  
  472. {I don't like that extra on the blitters; looks like a bug to me. I havn't checked what the problem is though. /Ingemar}
  473.         if gChosenBlitType = kDeepBlitType then
  474.             if theSize > 50 then
  475.                 MySetRect(spriteRect, pnt.h, pnt.v, pnt.h + theSize + 3, pnt.v + theSize + 3)
  476.             else
  477.                 MySetRect(spriteRect, pnt.h, pnt.v, pnt.h + theSize + 1, pnt.v + theSize + 1)
  478.         else
  479.             MySetRect(spriteRect, pnt.h, pnt.v, pnt.h + theSize, pnt.v + theSize);
  480.  
  481.         case gChosenBlitType of
  482.             kDeepBlitType: 
  483.                 begin
  484. {This animates the sprite. Notice it looks like CopyBits and CopyMasks,}
  485. {    only no scaling or special effects. Also, the GWorld parameters are different!}
  486.                     Copy8BitsII(bgWorld^.portPixMap, workWorld^.portPixMap, spriteRect2, spriteRect2);
  487.                     Mask8BitsII(spriteWorld^.portPixMap, maskWorld^.portPixMap, workWorld^.portPixMap, offRect, offMaskRect, spriteRect);
  488.                     tempRect := MergeRect(spriteRect2, spriteRect);
  489.                     Copy8BitsII(workWorld^.portPixMap, CGrafPtr(curPort)^.portPixMap, tempRect, tempRect);
  490.                 end;
  491.             kDeepCopyMaskType, kCopyBitsMaskType: 
  492.                 begin
  493. {This is copyBits and copyMask, either with deep mask (slow!) or 1-bit mask.}
  494.                     CopyBits(GrafPtr(bgWorld)^.portBits, GrafPtr(workWorld)^.portBits, spriteRect2, spriteRect2, srcCopy, nil);
  495.                     CopyMask(GrafPtr(spriteWorld)^.portBits, GrafPtr(maskWorld)^.portBits, GrafPtr(workWorld)^.portBits, offRect, offMaskRect, spriteRect);
  496.                     tempRect := MergeRect(spriteRect2, spriteRect);
  497.                     CopyBits(GrafPtr(workWorld)^.portBits, GrafPtr(curPort)^.portBits, tempRect, tempRect, srcCopy, nil);
  498.                 end;
  499.             kCopyBitsRgnType: 
  500.                 begin
  501. {This is copyBits with a mask region.}
  502.                     CopyBits(GrafPtr(bgWorld)^.portBits, GrafPtr(workWorld)^.portBits, spriteRect2, spriteRect2, srcCopy, nil);
  503.                     CopyRgn(maskRgn, tempRgn);
  504.                     OffsetRgn(tempRgn, spriteRect.left - offRect.left, spriteRect.top - offRect.top);
  505.                     CopyBits(GrafPtr(spriteWorld)^.portBits, GrafPtr(workWorld)^.portBits, offRect, spriteRect, srcCopy, tempRgn);
  506.                     tempRect := MergeRect(spriteRect2, spriteRect);
  507.                     CopyBits(GrafPtr(workWorld)^.portBits, GrafPtr(curPort)^.portBits, tempRect, tempRect, srcCopy, nil);
  508.                 end;
  509.             kCopyBitsRectType: 
  510.                 begin
  511. {This is just the copyBits with NO mask.}
  512.                     CopyBits(GrafPtr(bgWorld)^.portBits, GrafPtr(workWorld)^.portBits, spriteRect2, spriteRect2, srcCopy, nil);
  513.                     CopyBits(GrafPtr(spriteWorld)^.portBits, GrafPtr(workWorld)^.portBits, offRect, spriteRect, srcCopy, nil);
  514.                     tempRect := MergeRect(spriteRect2, spriteRect);
  515.                     CopyBits(GrafPtr(workWorld)^.portBits, GrafPtr(curPort)^.portBits, tempRect, tempRect, srcCopy, nil);
  516.                 end;
  517.         end; {case}
  518.  
  519.     {This makes spriteRect2 where the sprite WAS:}
  520.         MySetRect(spriteRect2, spriteRect.left, spriteRect.top, spriteRect.right, spriteRect.bottom);
  521.     until Button;
  522.  
  523. {This just shows how fast it all went:}
  524.     ForeColor(33);
  525.     finTime := TickCount;
  526.     lapseTime := finTime - initTime;
  527.     {numSecs := round(lapseTime / 60);}
  528.     {framesPerSec := round(frameCnt / numSecs);}
  529.     framesPerSec := frameCnt * 60 div lapseTime;
  530.     NumToString(framesPerSec, strBuff);
  531.     TextSize(24);
  532.     MoveTo(300, 80);
  533.     DrawString(strBuff);
  534. {MoveTo(340, 80);}
  535.     TextSize(12);
  536. {    strBuff := ('  Frames per Second ');}
  537.     DrawString(' frames per second ');
  538.     MoveTo(340, 435);
  539. {    StrBuff := ('Click the Mouse To Exit... ');}
  540.     DrawString('Click the mouse to exit... ');
  541.     repeat
  542.     until not Button;
  543.     repeat
  544.     until Button;
  545.     FlushEvents(mDownMask, 0);
  546. end.